﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int port = 888;
            TcpClient tcpClient;
            IPAddress[] serverIP = Dns.GetHostAddresses("127.0.0.1");   //定义IP地址
            IPAddress localAddress = serverIP[0];                       //IP地址  
            TcpListener tcpListener = new TcpListener(localAddress, port);          //监听套接字
            tcpListener.Start();
            //开始监听  
            Console.WriteLine("服务器启动成功，等待用户接入…");            //输出消息  
            while (true)
            {
                try
                {
                    tcpClient = tcpListener.AcceptTcpClient();          //每接收一个客户端则生成一个TcpClient  
                    NetworkStream networkStream = tcpClient.GetStream();//获取网络数据流
                    BinaryReader reader = new BinaryReader(networkStream);           //定义流数据读取对象
                    BinaryWriter writer = new BinaryWriter(networkStream);           //定义流数据写入对象
                    while (true)
                    {
                        try
                        {
                            var lengthdata = reader.ReadBytes(4);

                            var length = ReadInt(lengthdata, 0);
                            var data = reader.ReadBytes(length);
                            var id = ReadInt(data, 0);
                            //var data
                            Console.WriteLine("有客户端接入，客户消息长度：" + length);  //输出接收的客户端IP地址  
                            Console.WriteLine("来自客户端的消息id：" + id);        //输出接收的消息  
                            //Console.WriteLine("来自客户端的消息内容：" + data);
                            if (id == 1010)
                            {
                                Console.WriteLine("心跳包" );
                            }
                            LoginResponse res = new LoginResponse
                            {
                                Result = 1,
                                User = new User
                                {
                                    Base = new Base
                                    {
                                        UID = 10001,
                                        Name = "火箭奇侠"
                                    }
                                    ,
                                    Items = new List<Item>
                                    {
                                        new Item
                                        {
                                            Id=1,
                                            Num=10
                                        },
                                        new Item
                                        {
                                             Id=2,
                                            Num=10
                                        }
                                    }
                                }
                        };

                            var buffer = NSerialize(res);
                            // 总长度 = 数据包长度所占字节 + 协议号长度 + 协议内容长度
                            var intSize = sizeof(int); // 可以直接写死
                            var totalSize = intSize + intSize + buffer.Length;
                            // 为了书写方便而写的中间字节buffer类，其实可以暴力点直接处理byte[]还能省去这步
                            var byteBuffer = new ByteBuffer(totalSize);
                            // 写入数据长度
                            byteBuffer.WriteInt(totalSize - intSize);
                            // 写入协议号
                            byteBuffer.WriteInt(1001);
                            // 写入协议内容
                            byteBuffer.WriteBytes(buffer);
                            writer.Write(byteBuffer.GetBytes());                    //向对方发送消息  
                        }
                        catch
                        {
                            break;
                        }
                    }
                }
                catch
                {
                    break;
                }
            }


        }
        public static int ReadInt(byte[] buffer, int start)
        {
            return (buffer[start + 0] << 24 | buffer[start + 1] << 16 | buffer[start + 2] << 08 | buffer[start + 3] << 00);
        }

        public static byte[] NSerialize<T>(T t)
        {
            byte[] buffer = null;
            using (MemoryStream m = new MemoryStream())
            {
                Serializer.Serialize<T>(m, t);
                m.Position = 0;
                int length = (int)m.Length;
                buffer = new byte[length];
                m.Read(buffer, 0, length);
            }
            return buffer;
        }
    }

    [ProtoContract]
    public class LoginResponse
    {
        [ProtoMember(1)]
        public int Result;
        [ProtoMember(2)]
        public User User;
    }
    [ProtoContract]
    public class User
    {
        [ProtoMember(1)]
        public Base Base;
        [ProtoMember(2)]
        public List<Item> Items;
    }
    [ProtoContract]
    public class Base
    {
        [ProtoMember(1)]
        public int UID;
        [ProtoMember(2)]
        public string Name;
    }

    [ProtoContract]
    public class Item
    {
        [ProtoMember(1)]
        public int Id;
        [ProtoMember(2)]
        public int Num;
    }

    public class ByteBuffer
    {
        /// <summary>
        /// 容量
        /// </summary>
        private int mCapacity;
        /// <summary>
        /// 长度
        /// </summary>
        private int mLength;
        /// <summary>
        /// 字节数组
        /// </summary>
        private byte[] mBuffer;
        //=========================================================
        public int Capacity { get { return mCapacity; } }
        public int Length { get { return mLength; } }

        /// <summary>
        /// 构造
        /// </summary>
        public ByteBuffer(int capacity)
        {
            mCapacity = capacity;
            mLength = 0;
            mBuffer = new byte[capacity];
        }

        #region Write
        public void WriteInt(int value)
        {
            var pos = UpdateLength(4);
            mBuffer[pos + 0] = (byte)(value >> 24 & 0xFF);
            mBuffer[pos + 1] = (byte)(value >> 16 & 0xFF);
            mBuffer[pos + 2] = (byte)(value >> 08 & 0xFF);
            mBuffer[pos + 3] = (byte)(value >> 00 & 0xFF);
        }

        public void WriteBytes(byte[] value)
        {
            var pos = UpdateLength(value.Length);
            Buffer.BlockCopy(value, 0, mBuffer, pos, value.Length);
        }
        #endregion
        #region Read
        public int ReadInt(int start)
        {
            return (mBuffer[start + 0] << 24 | mBuffer[start + 1] << 16 | mBuffer[start + 2] << 08 | mBuffer[start + 3] << 00);
        }
        #endregion

        /// <summary>
        /// 更新长度
        /// </summary>
        public int UpdateLength(int writeLen)
        {
            if (mLength + writeLen > mCapacity)
            {
                throw new Exception("ByteBuffer out of capacity");
            }
            var pos = mLength;
            mLength += writeLen;
            return pos;
        }

        /// <summary>
        /// 获得字节数组
        /// </summary>
        public byte[] GetBytes()
        {
            return mBuffer;
        }

        /// <summary>
        /// 清除回收
        /// </summary>
        public void Clear()
        {
            mLength = 0;
            for (var i = 0; i < mBuffer.Length; i++)
            {
                mBuffer[i] = 0;
            }
        }
    }

}
